/*
 * @Author: yangrongxin
 * @Date: 2021-07-16 11:19:42
 * @LastEditors: liubin
 * @LastEditTime: 2021-11-16 14:39:55
 */
import Taro from '@tarojs/taro';
import wxLog from '@/utils/log';
import { STORAGE_TYPE } from '@/const/dataDictionary';
import { getItemSync, setItemSync, removeItem } from './storage';
import Cache from './cache';
import invokeRequest from './authentication';

const defaultParams = {
  appCode: API_APPCODE,
  channelCode: API_CHANNELCODE,
  appVersion: VERSION,
  requestType: 'MINI_PROGRAM',
};

/*
 * 与后端匹配的HTTP错误码
 */
const HTTP_ERROR = {
  '400': '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
  '401': '用户没有权限（令牌、用户名、密码错误）。',
  '403': '用户得到授权，但是访问是被禁止的。',
  '404': '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  '406': '请求的格式不可得。',
  '410': '请求的资源被永久删除，且不会再得到的。',
  '422': '当创建一个对象时，发生一个验证错误。',
  '500': '服务器发生错误，请检查服务器。',
  '502': '网关错误。',
  '503': '服务不可用，服务器暂时过载或维护。',
  '504': '网关超时。',
};

class RequestInstance {
  static count: number = 0; // 记录当前正在进行的请求数量
  static showLoading: boolean = false; // 控制当前是否在展示loading状态
  static instance: any;

  getInstance() {
    if (!RequestInstance.instance) {
      RequestInstance.instance = new RequestInstance();
    }
    return RequestInstance.instance;
  }

  /*
   * 检测当前的http状态值
   */
  static checkHttpStatus(response, options) {
    RequestInstance.count -= 1;

    console.log('url, uncount', options.tempUrl, RequestInstance.count);

    if (RequestInstance.showLoading && RequestInstance.count === 0) {
      Taro.hideLoading();
      RequestInstance.showLoading = false;
    }

    console.log('%c===网络请求出参===\n', 'color: #32b9aa', response?.data);

    if (response.statusCode >= 200 && response.statusCode < 300) {
      Taro.hideNavigationBarLoading();
      // 缓存当前返回信息
      if (options.cache) {
        Cache.saveCacheWidthName(options.tempUrl, options.data, response.data);
      }
      return response.data;
    }

    const message = HTTP_ERROR[response.statusCode] || `ERROR CODE: ${response.statusCode}`;
    Taro.showToast({
      title: message,
      icon: 'none',
      duration: 1500,
    });
  }

  /*
   * 检测当前是不是请求成功
   */
  static checkSuccess(response, isHideError) {
    const { code = '1', errCode, msg, returnCode = 200 } = response;
    console.log('response', response);
    // 隐藏当前请求的错误信息
    // if (isHideError) return response;
    if (isHideError) return response.data;

    if (code === '0' && errCode === '1110003') {
      Taro.navigateTo({
        url: '/pages/Login/index',
      });
      console.info('手机号获取失败');
      return;
    }

    if (code === '0' && errCode === '1110001') {
      Taro.navigateTo({
        url: '/pages/Login/index',
      });
      console.info('未携带token进行登录');
      return;
    }

    // 当前用户的账户在后台已经被禁用
    if (code === '0' && errCode === '1110002') {
      Taro.showToast({
        title: '当前账户已被禁用，请联系管理员',
        icon: 'none',
      });
      return;
    }

    // 用户未找到--可能是缓存的token异常 清空token重新登录
    if (code === '0' && errCode === '1110004') {
      removeItem('userInfo').then(() => {
        // 调用全局的登录信息 刷新token
        const { dispatch } = global._app.getStore();
        if (RequestInstance.count === 0)
          dispatch({
            type: 'global/loginWithCode',
          });
      });
      return;
    }

    // 制作游客流程 暂时进行屏蔽
    // || errCode === '1110001' 未携带token 请重新进行登录
    // 跳转到登录页面
    if (errCode === '401') {
      // 规定好走网关401是失效，但是后台有时候不走，要走1110001
      removeItem('userInfo').then(() => {
        // 调用全局的登录信息 刷新token
        const { dispatch } = global._app.getStore();
        if (RequestInstance.count === 0)
          dispatch({
            type: 'global/loginWithCode',
          });
      });
      return; // token失效取消提示
    }

    // 存在重复的未支付信息 跳转回首页
    if (errCode === '10001') {
      Taro.showToast({
        title: msg,
        icon: 'none',
        duration: 1500,
      });
      setTimeout(() => {
        Taro.reLaunch({
          url: '/pages/Home/index',
        });
      }, 1500);
      // 接口调用不成功直接返回false 而不是返回接口对应的数据
      return;
    }

    // returnCode 用于支付接口进行对应的判断
    if (code !== '1' || returnCode !== 200) {
      Taro.showToast({
        title: msg || HTTP_ERROR[errCode] || '未捕获到错误',
        icon: 'none',
        duration: 1500,
      });
      // 接口调用不成功直接返回false 而不是返回接口对应的数据
      return;
    }

    // return response
    return response.data;
  }

  /*
   * 检测错误
   */
  static throwError(error, url, isHideError, errorCallBack) {
    Taro.hideLoading();
    RequestInstance.showLoading = false;
    RequestInstance.count = 0;

    console.log('errorRequest', error);
    if (isHideError) return;
    if (error.errMsg) {
      // 当前是首页接口报错的时候进行统计
      if (wx.canIUse('reportPerformance')) {
        wx.reportPerformance('1001', url);
      }
      wxLog.warn(`接口请求失败${url}`);
    }
    if (error.errMsg) {
      console.log('url', url);
      if (typeof errorCallBack === 'function' && errorCallBack) {
        errorCallBack();
      } else {
        Taro.showToast({
          title: '网络异常，请稍后再试',
          icon: 'none',
          duration: 1500,
        });
      }
    }
  }

  /* 拼装对应的接口请求 */
  static generateUrl(prefix, url) {
    // 判断当前的请求地址是否需要进行补充
    const debuggerHost: any = SHOW_TEST_TOOLS === 'true' ? getItemSync('debuggerHost') : undefined;
    console.log('debuggerHost', debuggerHost);
    switch (prefix) {
      case 'API_BASE':
        return `${debuggerHost ? debuggerHost?.API_BASE : API_BASE}${url}`;
      case 'API_INTEGRAL':
        return `${debuggerHost ? debuggerHost?.API_INTEGRAL : API_INTEGRAL}${url}`;
      case 'API_PAY':
        return `${debuggerHost ? debuggerHost?.API_PAY : API_PAY}${url}`;
      default:
        return url;
    }
  }

  request(tempUrl, options) {
    const {
      method = 'POST',
      header,
      data,
      loading = false,
      title = '加载中',
      retryTimes = 0,
      errorCallBack,
      cache = false, // 是否缓存当前接口
      hideError = false, // 是否隐藏当前的错误信息
      prefix = 'API_BASE', // API_INTEGRAL 当前是否使用php接口
    } = options;

    // 增加请求计数 存在
    RequestInstance.count += 1;

    let url = RequestInstance.generateUrl(prefix, tempUrl);
    if (tempUrl.includes('http')) {
      url = tempUrl;
    }

    console.log('url, count', url, RequestInstance.count);

    // token 以及当前接口的鉴权参数
    // eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIzMzM2MjE0Mjc5MjYyMDQ0MTYxNjI3Mzc3ODcxNDc1IiwiaWF0IjoxNjI3Mzc3ODcyLCJzdWIiOiJ6bW1KbmJsTDhibG1jU1hHcmFUTGtTRzYwWW82WWhEWFlCUjlVemF4S1dGSTJRaHJqcUZQRlFVRjV2SngzSjMvcEtnWU8wbHpnNkJENVJiUVpPd054WStyeWNUblgrNXNGZkZDM2hQSmRsRmtRTVhMNmQ5UjU5UGFlRWJHa3lmcGcvRzJ0UEYzVzhDQWd5UU8xRCs0dDRBd0M2eWc3bktycGhHdXlaUjVHV3E3bE1DNXE3ekdjVHFtVEVVWU9uRmpWTDNadW02L2RzbUkvWnNtQ3paMHFWb1VUMFRFWHoxU0pva3Vxa2NLYlUxVkJtUFNvWTZpbkFNblZ1UW1Nd090U0REZWxlNUh0UDIxclZ2WTNKb3M5WXVXajFUS1pLR3g1VXE5VmFrdTV6TWNKbCt3Nm5KNzVQRFR5OEg2U0hvYU90Z3BBcWNWbkp6K3JjaHNmbmJ3L0FTZm1nL0dON1A4MjVhbXJQTjNuMWs9IiwiZXhwIjoxNjI5OTY5ODcyfQ.ElMHggtc6y-HHy7EFQCpHztbX3T-zul-01XunpHRe5Q***HXTAPP
    const { token: accessToken = '', Authorization = '' } = getItemSync(STORAGE_TYPE.USERINFO) || {};

    console.warn('storageUserInfo', getItemSync(STORAGE_TYPE.USERINFO));

    if (cache) {
      const curCacheData = Cache.getCacheWithName(tempUrl, data);
      if (curCacheData) {
        RequestInstance.count -= 1;
        if (RequestInstance.showLoading && RequestInstance.count === 0) {
          Taro.hideLoading();
          RequestInstance.showLoading = false;
        }
        return curCacheData;
      }
    }

    // 保证全局只有一个loading加载状态
    if (loading && !RequestInstance.showLoading) {
      RequestInstance.showLoading = true;
      Taro.showLoading({
        title,
      });
    }

    console.log(
      `%c===网络请求START===\n
        URL: ${url}\n
        METHOD: ${method}\n
        PAYLOAD: ${JSON.stringify({ ...defaultParams, ...data })}\n
  ===网络请求END===\n`,
      'color: #0376FF',
      { ...defaultParams, ...data },
      { token: accessToken },
    );

    return Taro.request({
      url,
      method: method.toUpperCase(),
      data: {
        ...defaultParams,
        ...invokeRequest(data),
      },
      header: {
        'Content-Type': 'application/json',
        accessToken,
        token: accessToken,
        Authorization,
        channelSource: 'largeTerminal',
        ...header,
      },
      timeout: 10000,
      retryTimes,
    })
      .then((response: any) =>
        RequestInstance.checkHttpStatus(response, {
          tempUrl,
          data,
          cache,
        }),
      )
      .then((response: any) => RequestInstance.checkSuccess(response, hideError))
      .catch((args) => RequestInstance.throwError(args, url, hideError, errorCallBack));
  }
}

export default new RequestInstance().getInstance().request;
